package org.mall.modules.cash.service.impl;

import cn.hutool.core.util.RandomUtil;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.domain.Participant;
import com.alipay.api.request.AlipayFundTransUniTransferRequest;
import com.alipay.api.response.AlipayFundTransUniTransferResponse;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.binarywang.wxpay.bean.entpay.EntPayRequest;
import com.github.binarywang.wxpay.bean.entpay.EntPayResult;
import com.github.binarywang.wxpay.constant.WxPayConstants;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.common.message.Message;
import org.mall.common.api.vo.Result;
import org.mall.common.constant.CashInfoLogResultEnum;
import org.mall.common.constant.CashTransactionStatusEnum;
import org.mall.common.constant.CommonConstant;
import org.mall.common.constant.PayChannelEnum;
import org.mall.common.exception.JeecgBootException;
import org.mall.common.system.util.JwtUtil;
import org.mall.common.util.*;
import org.mall.common.util.json.JacksonUtils;
import org.mall.modules.cash.entity.CashDetailInfo;
import org.mall.modules.cash.entity.CashInfoLog;
import org.mall.modules.cash.entity.CashTransaction;
import org.mall.modules.cash.mapper.CashDetailInfoMapper;
import org.mall.modules.cash.mapper.CashInfoLogMapper;
import org.mall.modules.cash.mapper.CashTransactionMapper;
import org.mall.modules.cash.service.ICashInfoLogService;
import org.mall.modules.message.service.AppMessageService;
import org.mall.modules.pay.client.PaySDKFactory;
import org.mall.modules.pojo.cash.CashInfoLogQueryDTO;
import org.mall.modules.pojo.common.AppMessageDTO;
import org.mall.modules.seller.mapper.SellerMapper;
import org.mall.modules.shop.mapper.ShopMapper;
import org.mall.modules.system.client.SmsClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;

/**
 * @Description: 提现信息记录表
 * @Author: jeecg-boot
 * @Date: 2019-12-31
 * @Version: V1.0
 */
@Service
@Slf4j
public class CashInfoLogServiceImpl extends ServiceImpl<CashInfoLogMapper, CashInfoLog> implements ICashInfoLogService {

    @Resource
    CashInfoLogMapper cashInfoLogMapper;
    @Resource
    CashDetailInfoMapper cashDetailInfoMapper;
    @Resource
    ShopMapper shopMapper;
    @Autowired
    private PaySDKFactory paySDKFactory;
    @Autowired
    private AlipayClient alipayClient;
    @Resource
    CashTransactionMapper transactionMapper;
    @Resource
    SellerMapper sellerMapper;
    @Qualifier("transactionService")
    @Autowired
    private WxPayService wxPayService;

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private AppMessageService appMessageService;

    @Autowired
    private SmsClient smsClient;

    @Autowired
    private DefaultMQProducer mqProducer;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean saveCashInfoLogDetails(List<CashInfoLog> cashInfoLog) {
        saveBatch(cashInfoLog);
        List<CashDetailInfo> list=new ArrayList<>();
        for (CashInfoLog cashDetailInfos : cashInfoLog) {
            list.addAll(cashDetailInfos.getDetailInfos());
        }
        cashDetailInfoMapper.insertBatch(list);
        return true;
    }

    @Override
    public IPage<CashInfoLog> pageList(Page<CashInfoLog> page, QueryWrapper<CashInfoLog> queryWrapper) {
        return cashInfoLogMapper.pageList(page, queryWrapper);
    }

    @Override
    public CashInfoLog getDetailById(Long infoId) {
        return cashInfoLogMapper.getDetailById(infoId);
    }

    @Override
    public Boolean confirm(Long cashInfoLogId,Integer payChannel) {
        if (redisUtil.hasKey(String.valueOf(cashInfoLogId))){
            throw new JeecgBootException("请求过于频繁");
        }
        redisUtil.setBindKey(String.valueOf(cashInfoLogId));

        CashInfoLog cashInfoLog = getById(cashInfoLogId);
        CashTransaction query=transactionMapper.selectByCashIdAndStatus(cashInfoLogId,CashTransactionStatusEnum.SUCCESS.getValue());
        if (query!=null){
            return false;
        }
        if (cashInfoLog ==
                null || !CashInfoLogResultEnum.REVIEWING.getValue().equals(cashInfoLog.getResult())) {
            throw new JeecgBootException("此条提交记录不存在");
        }
        if (cashInfoLog.getPresentPrice() != cashInfoLog.getDetailInfos().stream().mapToInt(CashDetailInfo::getPresentPrice).sum()) {
            throw new JeecgBootException("金额错误，不能创建支付");
        }
        cashInfoLog.setResult(CashInfoLogResultEnum.SUCCESS.getValue());
        CashTransaction transaction ;
        if (PayChannelEnum.WEIXIN_APP.getId().equals(payChannel)){

        EntPayRequest entPayRequest = new EntPayRequest();
        entPayRequest.setOpenid(cashInfoLog.getWxOpenId());
        entPayRequest.setSpbillCreateIp(IPUtils.getIpAddr());
        entPayRequest.setDescription("用户提现");
        entPayRequest.setCheckName(WxPayConstants.CheckNameOption.NO_CHECK);
        entPayRequest.setNonceStr(RandomUtil.randomString(32));
            transaction = new CashTransaction();
            transaction.setId(GeneratorSnowFlakeIDUtils.nextId());
            transaction.setStatus(CashTransactionStatusEnum.WATING.getValue());
            transaction.setCashId(cashInfoLogId);
            transaction.setCreateIp(IPUtils.getIpAddr());
            transaction.setCreateTime(new Date());
            transaction.setPrice(cashInfoLog.getPresentPrice());
            transaction.setTradeNo(String.valueOf(GeneratorSnowFlakeIDUtils.nextId()));
            int num = transactionMapper.insert(transaction);
            if (num == 0) {
                throw new JeecgBootException("保存交易记录失败");
        }
        {
            entPayRequest.setPartnerTradeNo(transaction.getTradeNo());
            entPayRequest.setAmount(cashInfoLog.getPresentPrice());
        }
        if (!submitWxCashTransaction(entPayRequest, transaction)){
            cashInfoLog.setResult(CashInfoLogResultEnum.PAYING.getValue());
            }
        }
        if (PayChannelEnum.ALIPAY.getId().equals(payChannel)){
            CashTransaction updateObj=new CashTransaction();
                transaction = new CashTransaction();
                transaction.setId(GeneratorSnowFlakeIDUtils.nextId());
                transaction.setStatus(CashTransactionStatusEnum.WATING.getValue());
                transaction.setCashId(cashInfoLogId);
                transaction.setCreateIp(IPUtils.getIpAddr());
                transaction.setCreateTime(new Date());
                transaction.setPrice(cashInfoLog.getPresentPrice());
                transaction.setTradeNo(String.valueOf(GeneratorSnowFlakeIDUtils.nextId()));
                int num = transactionMapper.insert(transaction);
                if (num == 0) {
                    throw new JeecgBootException("保存交易记录失败");
             }
            try{
                AlipayFundTransUniTransferRequest request = new AlipayFundTransUniTransferRequest();
                JSONObject jsonObject=new JSONObject();
                Participant participant=new Participant();
                participant.setIdentityType("ALIPAY_USER_ID");
                participant.setIdentity(cashInfoLog.getWxOpenId());
                jsonObject.put("out_biz_no",transaction.getTradeNo());
                BigDecimal price=new BigDecimal(transaction.getPrice());
                jsonObject.put("trans_amount",price.divide(new BigDecimal(100),2,BigDecimal.ROUND_HALF_UP).toString());
                jsonObject.put("biz_scene",String.valueOf(transaction.getCashId()));
                jsonObject.put("payee_info",participant);
                jsonObject.put("order_title","然气惠民会员商城提现");

                AlipayFundTransUniTransferResponse response =  alipayClient.certificateExecute(request);
                if (response.isSuccess()&&"SUCCESS".equals(response.getStatus())){
                    updateObj.setUpdateTime(new Date());
                    updateObj.setId(transaction.getId());
                    updateObj.setStatus(CashTransactionStatusEnum.SUCCESS.getValue());
                    transactionMapper.updateById(updateObj);

                }
            }catch (AlipayApiException e){
                cashInfoLog.setResult(CashInfoLogResultEnum.PAYING.getValue());
                    updateObj.setStatus(CashTransactionStatusEnum.PAYING.getValue());
                    updateObj.setId(transaction.getId());
                    updateObj.setUpdateTime(new Date());
                    transactionMapper.updateById(updateObj);
                    mqProducer.setProducerGroup("error-cashTransaction" + CommonConstant.ORDER_EXPIRE);
                    try {
                        Message sendMsg = new Message(CommonConstant.ERROR_TRANACTION,
                                "rocketTag",
                                "", JacksonUtils.toJSONString(updateObj).getBytes());
                        sendMsg.setDelayTimeLevel(1);
                        mqProducer.send(sendMsg);
                    } catch (Exception o) {
                        o.printStackTrace();
                }
            }
        }
        cashInfoLog.setPayChannel(payChannel);
        this.updateById(cashInfoLog);
        redisUtil.delBindKey(String.valueOf(cashInfoLogId));
        AppMessageDTO appMessageDTO = new AppMessageDTO();
        appMessageDTO.setTitle("然气惠民");
        appMessageDTO.setContent("您于"+ DateUtils.formatDate(new Date()) + "成功提现" + (double)cashInfoLog.getPresentPrice() / 100 +"元");
        appMessageDTO.setCreateTime(DateUtils.getDate());
        appMessageDTO.setTemplateId(1);
        appMessageDTO.setCreator("");
        appMessageDTO.setReceiver(JwtUtil.getUserIdByToken());
        appMessageService.sendAppMessageToUser(appMessageDTO);
        String mobile = sellerMapper.getMobileById(cashInfoLog.getSellerId());
        Map<String,String> map = new HashMap<>();
        map.put("content","您于"+ DateUtils.formatDate(new Date()) + "成功提现" + (double)cashInfoLog.getPresentPrice() / 100 +"元");
        smsClient.singleSendMsg(mobile,map);
        return true;
    }

    @Override
    public Boolean refuse(Long cashInfoLogId, String response) {

        CashInfoLog cashInfoLog = cashInfoLogMapper.selectById(cashInfoLogId);
        if (!cashInfoLog.getResult().equals(CashInfoLogResultEnum.REVIEWING.getValue())) {
            return false;
        }

        cashInfoLog.setResult(CashInfoLogResultEnum.FAILURE.getValue());
        cashInfoLog.setResponse(response);
        cashInfoLog.setAdminUserId(JwtUtil.getUserIdByToken());
        cashInfoLog.setUpdateTime(new Date());
        cashInfoLogMapper.updateById(cashInfoLog);

        AppMessageDTO appMessageDTO = new AppMessageDTO();
        appMessageDTO.setTitle("然气惠民");
        appMessageDTO.setContent("然气惠民平台在"+ DateUtils.formatDate(new Date()) + "拒绝了您提现" +(double) cashInfoLog.getPresentPrice() / 100 +"元的请求");
        appMessageDTO.setCreateTime(DateUtils.getDate());
        appMessageDTO.setTemplateId(1);
        appMessageDTO.setCreator("");
        appMessageDTO.setReceiver(JwtUtil.getUserIdByToken());
        appMessageService.sendAppMessageToUser(appMessageDTO);
        String mobile = sellerMapper.getMobileById(cashInfoLog.getSellerId());
        Map<String,String> map = new HashMap<>();
        map.put("content","然气惠民平台在"+ DateUtils.formatDate(new Date()) + "拒绝了您提现" +(double) cashInfoLog.getPresentPrice() / 100 +"元的请求");
        smsClient.singleSendMsg(mobile,map);
        return true;
    }

    @Override
    public Result<?> getTransactionLog(Long cashId) {
        CashTransaction cashTransaction = transactionMapper.selectByCashId(cashId);

        return Result.ok(cashTransaction);
    }

    @Override
    public IPage<CashInfoLog> pageListByCondition(Page page, CashInfoLogQueryDTO cashInfoLog) {
        return cashInfoLogMapper.pageListByCondition(page,cashInfoLog.getSellerId(),cashInfoLog.getCreateStartTime(),cashInfoLog.getCreateEndTime(),cashInfoLog.getResult(),cashInfoLog.getId());
    }


    public boolean submitWxCashTransaction(EntPayRequest request, CashTransaction cashTransaction) {
        try {
            EntPayResult result = wxPayService.getEntPayService().entPay(request);
            if (WxPayConstants.ResultCode.SUCCESS.equals(result.getReturnCode())) {
                if (WxPayConstants.ResultCode.SUCCESS.equals(result.getResultCode())) {
                    cashTransaction.setStatus(CashTransactionStatusEnum.SUCCESS.getValue());
                    cashTransaction.setUpdateTime(new Date());
                    cashTransaction.setPaymentTime(DateUtil.parsDateString(result.getPaymentTime(),"yyyy-MM-dd HH:mm:ss"));
                    return true;
                } else {
                    cashTransaction.setStatus(CashTransactionStatusEnum.FAILURE.getValue());
                    cashTransaction.setErrorCode(result.getErrCode());
                    cashTransaction.setErrorMessage(result.getErrCodeDes());
                    cashTransaction.setResponse("错误代码:" + result.getErrCode() + "\r错误原因:" + result.getErrCodeDes());
                }
            } else {
                cashTransaction.setStatus(CashTransactionStatusEnum.FAILURE.getValue());
                cashTransaction.setResponse("通信错误:" + result.getReturnMsg());
            }
        } catch (WxPayException e) {
            cashTransaction.setUpdateTime(new Date());
            cashTransaction.setStatus(CashTransactionStatusEnum.PAYING.getValue());
            mqProducer.setProducerGroup("error-cashTransaction" + CommonConstant.ORDER_EXPIRE);
            try {
                Message sendMsg = new Message(CommonConstant.ERROR_TRANACTION,
                        "rocketTag",
                        "", JacksonUtils.toJSONString(cashTransaction).getBytes());
                sendMsg.setDelayTimeLevel(1);
                mqProducer.send(sendMsg);
            } catch (Exception o) {
                o.printStackTrace();
            }
            return true;
        } finally {
            transactionMapper.updateById(cashTransaction);
        }

        return false;
    }


}
